﻿using Abp.Extensions;
using Abp.Json;
using Mt.Site.Core.WorkFlows.Process.Entities;
using Mt.Site.Core.WorkFlows.Process.Stores;
using System;
using System.Collections.Generic;
using System.Threading.Tasks;

namespace Mt.Site.Core.WorkFlows.Process.Models
{
    /// <summary>
    /// 表单字段的备份和还原（不支持大字段（contentBody））
    /// </summary>
    public class FormDataCache
    {
        public bool ReSetFormData { get; set; }

        public Dictionary<string, string> Values { get; set; }
        public FormDataCache()
        {
            Values = new Dictionary<string, string>();
        }

        public async Task BackupData(
            UpdateFormDataInput input,
            IWorkFlowFormDataStore workFlowFormDataStore,
            IWorkFlowManager workFlowManager,
            Action<Dictionary<string, string>> action = null)
        {
            var isbranch = await workFlowManager.IsBranchLineAsync();
            var actionState = await workFlowManager.CheckActionStateAsync();
            var fields = await workFlowFormDataStore.GetFieldPermissionAsync(workFlowManager.WorkFlow, workFlowManager.NodeId, workFlowManager);
            foreach (var field in fields)
            {
                if (field.CanEdit)
                {
                    Values[field.CamelCaseKey] = input.Values.ContainsKey(field.CamelCaseKey) ? input.Values[field.CamelCaseKey] : "";
                }
            }
            action?.Invoke(Values);

            // 恢复表单数据 (避免把临时数据更新到数据库去)
            var data = await workFlowFormDataStore.GetAllFieldAsync(workFlowManager.PaperId);
            foreach (var field in fields)
            {
                if (field.CanEdit)
                {
                    input.Values[field.CamelCaseKey] = (data.ContainsKey(field.PascalCaseKey) ? data[field.PascalCaseKey] : "");
                }
            }
        }

        public async Task Renew(
            IWorkFlowFormDataStore workFlowFormDataStore,
            IWorkFlowManager workFlowManager, 
            FormDataOutput output,
            Action<Dictionary<string, string>, FormDataOutput> action = null)
        {
            action?.Invoke(Values, output);

            var fields = await workFlowFormDataStore.GetFieldPermissionAsync(workFlowManager.WorkFlow, workFlowManager.NodeId, workFlowManager);
            foreach (var field in fields)
            {
                if (field.CanEdit)
                {
                    if (Values.ContainsKey(field.CamelCaseKey))
                    {
                        output.FormData.Data[field.CamelCaseKey] = Values[field.CamelCaseKey];
                    }
                }
            }
        }

        public async Task<FormDataCache> UpdateFormData(IWorkFlowManager workFlowManager, IWorkFlowFormDataStore workFlowFormDataStore,
            Action<Dictionary<string, string>> action = null,
            Action<WorkFlowPaper, Dictionary<string, string>> updatePaperAction = null)
        {
            //将缓存数据更新到表中，将表中的数据保存到缓存中 
            var copy = new FormDataCache();
            copy.ReSetFormData = true;

            var data = await workFlowFormDataStore.GetAllFieldAsync(workFlowManager.PaperId);


            var fields = await workFlowFormDataStore.GetFieldPermissionAsync(workFlowManager.WorkFlow, workFlowManager.NodeId, workFlowManager);
            foreach (var field in fields)
            {
                if (field.CanEdit)
                {
                    copy.Values[field.CamelCaseKey] = (data.ContainsKey(field.PascalCaseKey) ? data[field.PascalCaseKey] : "");
                }
            }

            action?.Invoke(copy.Values);

            await SaveCacheToDbAsync(workFlowManager.CurrentPaper.Paper, workFlowFormDataStore, fields, updatePaperAction);

            return copy;
        }

        public async Task UpdateFormDataForRollback(WorkFlowPaper paper, IWorkFlowFormDataStore workFlowFormDataStore, 
            List<FormDataItemDescription> fields,
            Action<WorkFlowPaper, Dictionary<string, string>> updatePaperAction = null)
        {
            await SaveCacheToDbAsync(paper, workFlowFormDataStore, fields, updatePaperAction);
        }

        private async Task SaveCacheToDbAsync(WorkFlowPaper paper, IWorkFlowFormDataStore workFlowFormDataStore, List<FormDataItemDescription> fields,
            Action<WorkFlowPaper, Dictionary<string, string>> updatePaperAction = null)
        {
            updatePaperAction?.Invoke(paper, this.Values);

            var paperId = paper.Id;
            foreach (var field in fields)
            {
                if (field.CanEdit)
                {
                    if (Values.ContainsKey(field.CamelCaseKey))
                    {
                        await workFlowFormDataStore.UpdateSpecialFieldAsync(field.PascalCaseKey, paperId, Values[field.CamelCaseKey]);
                    }
                }
            }
        }

        public Dictionary<string, string> GetSpecialField(List<string> keys)
        {
            var result = new Dictionary<string, string>();

            foreach (var key in keys)
            {
                var keyCamelCase = key.ToCamelCase();
                if (Values.ContainsKey(keyCamelCase))
                {
                    result[key] = Values[keyCamelCase];
                }
            }

            return result;
        }

        public string GetSpecialField(string key)
        {
            var keyCamelCase = key.ToCamelCase();
            if (Values.ContainsKey(keyCamelCase))
            {
                return Values[keyCamelCase];
            }

            return "";
        }

        public static FormDataCache Parse(string str)
        {
            if (!str.IsNullOrEmpty())
            {
                try
                {
                    var data = str.FromJsonString<FormDataCache>();
                    if (data != null)
                    {
                        return data;
                    }
                }
                catch { }

                throw new Exception($"缓存数据不存在");
            }
            else
            {
                throw new Exception($"缓存数据不存在");
            }
        }
    }
}
